<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="用户授权" tabindex="-1"><a class="header-anchor" href="#用户授权"><span>用户授权</span></a></h2>
<ul>
<li><a href="#introduction">简介</a></li>
<li><a href="#gates">Gates</a>
<ul>
<li><a href="#writing-gates">编写 Gates</a></li>
<li><a href="#authorizing-actions-via-gates">授权动作</a></li>
<li><a href="#gate-responses">Gate 响应</a></li>
<li><a href="#intercepting-gate-checks">Gate 拦截检查</a></li>
</ul>
</li>
<li><a href="#creating-policies">创建策略</a>
<ul>
<li><a href="#generating-policies">生成策略</a></li>
<li><a href="#registering-policies">注册策略</a></li>
</ul>
</li>
<li><a href="#writing-policies">编写策略</a>
<ul>
<li><a href="#policy-methods">策略方法</a></li>
<li><a href="#policy-responses">Policy 响应</a></li>
<li><a href="#methods-without-models">不包含模型方法</a></li>
<li><a href="#guest-users">访客-用户</a></li>
<li><a href="#policy-filters">策略过滤器</a></li>
</ul>
</li>
<li><a href="#authorizing-actions-using-policies">使用策略去授权动作</a>
<ul>
<li><a href="#via-the-user-model">通过用户模型</a></li>
<li><a href="#via-middleware">通过中间件</a></li>
<li><a href="#via-controller-helpers">通过控制器辅助函数</a></li>
<li><a href="#via-blade-templates">通过 Blade 模板</a></li>
<li><a href="#supplying-additional-context">提供上下文</a></li>
</ul>
</li>
</ul>
<h2 id="简介" tabindex="-1"><a class="header-anchor" href="#简介"><span>简介</span></a></h2>
<p>除了提供开箱即用的 <a href="https://learnku.com/docs/laravel/6.x/authentication" target="_blank" rel="noopener noreferrer">用户认证</a> 服务外，Laravel还提供了一种简单的方法来处理用户的授权动作。与用户认证一样，Laravel的授权方法很简单，授权操作有两种主要方式：gates和策略。</p>
<p>可以把 gates 和策略比作路由和控制器。Gates提供了一种简单的基于闭包的授权方法，而策略和控制器类似，围绕特定模型或资源对其逻辑进行分组来实现授权认证。我们先探索gates，然后研究策略。</p>
<p>在构建一个应用的时候，不用在专门使用 gates 或者只使用策略之间进行选择。大部分应用很可能同时包含 gates 和策略， 并且能够很好的进行工作。 Gates 大部分应用在模型和资源没有关系的地方，比如查看管理员的面板。与之相反，策略应该在特定的模型或者资源中使用。</p>
<h2 id="gates" tabindex="-1"><a class="header-anchor" href="#gates"><span>Gates</span></a></h2>
<h3 id="编写-gates" tabindex="-1"><a class="header-anchor" href="#编写-gates"><span>编写 Gates</span></a></h3>
<p>Gates 是用来决定用户是否授权执行给予动作的一个闭包函数，并且典型的做法就是在 <code v-pre>App\Providers\AuthServiceProvider</code> 中使用 <code v-pre>Gate</code> 来定义. Gates 总是接收一个用户实例作为第一个参数，并且可以接收可选参数，比如相关的 Eloquent 模型：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 注册任意用户认证、用户授权服务。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">void</span></span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">registerPolicies</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">isAdmin</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Gates 也可以使用类似控制器方法 <code v-pre>Class@method</code> 风格的回调字符串来定义：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 注册任意用户认证、用户授权服务。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">void</span></span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">registerPolicies</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'App\Policies\PostPolicy@update'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="授权动作" tabindex="-1"><a class="header-anchor" href="#授权动作"><span>授权动作</span></a></h3>
<p>使用 Gate 来授权动作的时候， 你应该使用 <code v-pre>allows</code> 或者 <code v-pre>denies</code> 方法。 注意，不需要将当前已认证用户传递给这些方法。 Laravel 会自动处理好已经认证通过的用户，然后传递给 Gate 闭包函数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">allows</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 指定当前用户可以编辑设置</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">allows</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 指定当前用户可以进行更新...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">denies</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 指定当前用户不能更新...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果你想判断一个特定的用户是否已经被授权访问某个动作， 你可以使用在 <code v-pre>Gate</code> 在facade的 <code v-pre>forUser</code> 方法:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">forUser</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">allows</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户可以更新...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">forUser</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">denies</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户不能更新...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>您可以使用 <code v-pre>any</code> 或 <code v-pre>none</code> 方法一次授权多个操作：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">any</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'delete-post'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户可以更新或删除</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">none</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'delete-post'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 用户不能更新或删除</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="授权或抛出异常" tabindex="-1"><a class="header-anchor" href="#授权或抛出异常"><span>授权或抛出异常</span></a></h4>
<p>如果要尝试对某个操作进行授权，并在未授权用户进行该操作的情况下抛出 <code v-pre>illuminate\auth\access\authorizationexception</code>，则可以使用 <code v-pre>gate::authorize</code>方法。<code v-pre>authorizationexception</code> 的实例将自动转换为 <code v-pre>403</code> http 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update-post'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 当前行为已授权...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="提供上下文" tabindex="-1"><a class="header-anchor" href="#提供上下文"><span>提供上下文</span></a></h4>
<p>能够用于授权的 Gate 方法（<code v-pre>allows</code>，<code v-pre>denies</code>，<code v-pre>check</code>，<code v-pre>any</code>，<code v-pre>none</code>，<code v-pre>authorize</code>，<code v-pre>can</code>，<code v-pre>cannot</code>）和授权[blade directives]（<code v-pre>@can</code>，<code v-pre>@cannot</code>，<code v-pre>@canany</code>）可以接收一个数组作为第二个参数。这些数组元素作为参数传递给 gate ，在做出授权决策时可用于其他上下文：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create-post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token variable">$category</span><span class="token punctuation">,</span> <span class="token variable">$extraFlag</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$category</span><span class="token operator">-></span><span class="token property">group</span> <span class="token operator">></span> <span class="token number">3</span> <span class="token operator">&amp;&amp;</span> <span class="token variable">$extraFlag</span> <span class="token operator">===</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">check</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create-post'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token variable">$category</span><span class="token punctuation">,</span> <span class="token variable">$extraFlag</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// The user can create the post...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="gate-响应" tabindex="-1"><a class="header-anchor" href="#gate-响应"><span>Gate 响应</span></a></h3>
<p>到目前为止，我们只检查了返回简单布尔值的 Gate 。但是，有时你可能希望返回更详细的响应，包括错误消息。为此，你可以从你的 Gate 返回<code v-pre>illuminate\auth\access\response</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">isAdmin</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">deny</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'You must be a super administrator.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>从 Gate 返回授权响应时，<code v-pre>gate::allows</code> 方法仍将返回一个简单的布尔值；但是可以使用 <code v-pre>gate::inspect</code> 方法获取 Gate 返回的完整授权响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">inspect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">allowed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前行为已授权...</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">echo</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当然，当使用 <code v-pre>gate::authorize</code> 方法抛出 <code v-pre>authorizationexception</code> 时，如果操作未经授权，则授权响应提供的错误消息将传播到 http 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'edit-settings'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">//  当前行为已授权...</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="gate-拦截检查" tabindex="-1"><a class="header-anchor" href="#gate-拦截检查"><span>Gate 拦截检查</span></a></h3>
<p>有时，你可能希望将所有能力授予特定用户。所以你可以在所有其他授权检查之前使用 <code v-pre>before</code> 方法来定义运行的回调：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">before</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token variable">$ability</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isSuperAdmin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果 <code v-pre>before</code> 回调方法返回的是非 null 的结果，则结果将被视为检查结果。</p>
<p>您可以使用 <code v-pre>after</code> 方法，定义一个在所有其他授权检查后执行的回调：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token variable">$ability</span><span class="token punctuation">,</span> <span class="token variable">$result</span><span class="token punctuation">,</span> <span class="token variable">$arguments</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isSuperAdmin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>与 <code v-pre>before</code> 检查类似，如果 <code v-pre>after</code> 回调返回非 null 结果，则结果将被视为检查结果。</p>
<h2 id="创建策略" tabindex="-1"><a class="header-anchor" href="#创建策略"><span>创建策略</span></a></h2>
<h3 id="生成策略" tabindex="-1"><a class="header-anchor" href="#生成策略"><span>生成策略</span></a></h3>
<p>策略是在特定模型或者资源中组织授权逻辑的类。例如，你的应用是一个博客，那么你在创建或者更新博客的时候，你可能会有一个 <code v-pre>Post</code> 模型和一个对应的 <code v-pre>PostPolicy</code> 来授权用户动作。</p>
<p>可以使用 <code v-pre>make:policy</code> <a href="https://learnku.com/docs/laravel/6.x/artisan" target="_blank" rel="noopener noreferrer">artisan command</a> 生成策略。 生成的策略将放在 <code v-pre>app/Policies</code> 目录。如果您的应用程序中不存在此目录，Laravel 将为您创建它：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">php artisan make<span class="token punctuation">:</span>policy PostPolicy</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>make:policy</code> 命令将生成一个空策略类。如果你想生成一个包含基本的 “CRUD” 策略方法的类，你可以在执行命令时指定一个 <code v-pre>--model</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">php artisan make<span class="token punctuation">:</span>policy PostPolicy <span class="token operator">--</span>model<span class="token operator">=</span>Post</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>建议：所有策略都通过 Laravel 解析 <a href="https://learnku.com/docs/laravel/6.x/container" target="_blank" rel="noopener noreferrer">service container</a>，允许您在策略的构造函数中键入提示任何需要的依赖项，以便自动注入它们。</p>
</blockquote>
<h3 id="注册策略" tabindex="-1"><a class="header-anchor" href="#注册策略"><span>注册策略</span></a></h3>
<p>一旦策略存在，就需要注册它。新 Laravel 应用程序中包含的 <code v-pre>AuthServiceProvider</code> 包含一个 <code v-pre>policy</code> 属性，它将您的 Eloquent 模型映射到它们相应的策略。注册一个策略将指导 Laravel 在授权针对给定模型的操作时使用哪个策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Providers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Policies<span class="token punctuation">\</span>PostPolicy</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Providers<span class="token punctuation">\</span>AuthServiceProvider</span> <span class="token keyword">as</span> ServiceProvider<span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">AuthServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 应用程序的策略映射。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@var</span> <span class="token class-name"><span class="token keyword">array</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">protected</span> <span class="token variable">$policies</span> <span class="token operator">=</span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span> <span class="token operator">=></span> <span class="token class-name static-context">PostPolicy</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 注册任何应用程序 authentication / authorization 服务。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">void</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">registerPolicies</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">//</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="策略自动发现" tabindex="-1"><a class="header-anchor" href="#策略自动发现"><span>策略自动发现</span></a></h4>
<p>不需要手动注册模型策略，只要模型和策略遵循标准的 Laravel 命名约定，Laravel 就可以自动发现策略。具体来说，策略必须位于包含模型的目录下的 <code v-pre>Policies</code> 目录中。例如，模型可以放在 <code v-pre>app</code> 目录中，而策略可以放在 <code v-pre>app/Policies</code> 目录中。此外，策略名称必须与模型名称匹配，并具有 <code v-pre>Policy</code> 后缀。因此，一个 <code v-pre>User</code> 模型将对应于一个 <code v-pre>UserPolicy</code> 类。</p>
<p>如果希望提供自己的策略发现逻辑，可以使用 <code v-pre>Gate::guessPolicyNamesUsing</code> 方法注册自定义回调。通常，这个方法应该从应用程序的 <code v-pre>AuthServiceProvider</code> 的 <code v-pre>boot</code> 方法中调用:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Support<span class="token punctuation">\</span>Facades<span class="token punctuation">\</span>Gate</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">guessPolicyNamesUsing</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$modelClass</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 返回策略类名…</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>注意：在 <code v-pre>AuthServiceProvider</code> 中显式映射的任何策略都将优先于任何潜在的自动发现策略。</p>
</blockquote>
<h2 id="编写策略" tabindex="-1"><a class="header-anchor" href="#编写策略"><span>编写策略</span></a></h2>
<h3 id="策略方法" tabindex="-1"><a class="header-anchor" href="#策略方法"><span>策略方法</span></a></h3>
<p>一旦注册了策略，您可以为它授权的每个操作添加方法。例如，让我们在 <code v-pre>PostPolicy</code> 上定义一个 <code v-pre>update</code> 方法，它确定给定的 <code v-pre>User</code> 是否可以更新给定的 <code v-pre>Post</code> 实例。</p>
<p><code v-pre>update</code> 方法将接收一个 <code v-pre>User</code> 和一个 <code v-pre>Post</code> 实例作为参数，并应返回 <code v-pre>true</code> 或 <code v-pre>false</code>，指示用户是否被授权更新给定的 <code v-pre>Post</code>。所以，在这个例子中，让我们验证用户的 <code v-pre>id</code> 是否与帖子上的 <code v-pre>user_id</code> 匹配：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Policies</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostPolicy</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 确定用户是否可以更新给定的帖子。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>User</span>  <span class="token parameter">$user</span></span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Post</span>  <span class="token parameter">$post</span></span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">bool</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>您可以根据策略授权的各种操作的需要，继续在策略上定义其他方法。例如，您可以定义 <code v-pre>view</code> 或 <code v-pre>delete</code> 方法来授权各种 <code v-pre>Post</code> 操作，但请记住，您可以自由地为策略方法指定任何名称。</p>
<blockquote>
<p>建议： 如果您在通过 Artisan 控制台生成策略时使用了 <code v-pre>--model</code> 选项，那么它已经包含了 <code v-pre>view</code>、<code v-pre>create</code>、<code v-pre>update</code>、<code v-pre>delete</code>、<code v-pre>restore</code> 和 <code v-pre>forceDelete</code> 操作的方法。</p>
</blockquote>
<h3 id="策略响应" tabindex="-1"><a class="header-anchor" href="#策略响应"><span>策略响应</span></a></h3>
<p>到目前为止，我们只研究了返回简单布尔值的策略方法。然而，有时您可能希望返回更详细的响应，包括错误消息。为此，您可以从您的策略方法返回一个<code v-pre>\Auth\Access\Response</code>：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>Response</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>User</span>  <span class="token parameter">$user</span></span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Post</span>  <span class="token parameter">$post</span></span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">bool</span></span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span></span>
<span class="line">                <span class="token operator">?</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">allow</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">                <span class="token punctuation">:</span> <span class="token class-name static-context">Response</span><span class="token operator">::</span><span class="token function">deny</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'You do not own this post.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当从策略返回授权响应时，<code v-pre>Gate::allows</code> 方法仍然返回一个简单的布尔值；但是，您可以使用 <code v-pre>Gate::inspect</code> 方法来获得Gate返回的完整授权响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token variable">$response</span> <span class="token operator">=</span> <span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">inspect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$response</span><span class="token operator">-></span><span class="token function">allowed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// The action is authorized...</span></span>
<span class="line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">echo</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>当然，当使用 <code v-pre>Gate::authorize</code> 方法在未授权操作时抛出 <code v-pre>AuthorizationException</code>，授权响应提供的错误消息将传播到 HTTP 响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Gate</span><span class="token operator">::</span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token comment">// 该行动被授权…</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="不包含模型方法" tabindex="-1"><a class="header-anchor" href="#不包含模型方法"><span>不包含模型方法</span></a></h3>
<p>一些策略方法只接收当前经过身份验证的用户，而不接收它们授权的模型的实例。这种情况在授权 <code v-pre>create</code> 操作时最为常见。例如，如果您正在创建博客，您可能希望检查用户是否被授权创建任何帖子。</p>
<p>当定义不接收模型实例的策略方法时，例如 <code v-pre>create</code> 方法，它将不接收模型实例。相反，您应该将方法定义为只期望经过身份验证的用户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定给定用户是否可以创建帖子。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>User</span>  <span class="token parameter">$user</span></span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">bool</span></span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">create</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="guest-用户" tabindex="-1"><a class="header-anchor" href="#guest-用户"><span>Guest 用户</span></a></h3>
<p>默认情况下，如果传入的 HTTP 请求不是由经过身份验证的用户发起的，所有的门和策略都会自动返回 <code v-pre>false</code>。但是，您可以通过声明一个「可选」类型提示或为用户参数定义提供一个 <code v-pre>null</code> 默认值，从而允许这些授权检查通过您的门和策略:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Policies</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>User</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostPolicy</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 确定用户是否可以更新给定的帖子。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>User</span>  <span class="token parameter">$user</span></span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Post</span>  <span class="token parameter">$post</span></span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">bool</span></span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token operator">?</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="策略过滤器" tabindex="-1"><a class="header-anchor" href="#策略过滤器"><span>策略过滤器</span></a></h3>
<p>对于某些用户，您可能希望授权给定策略中的所有操作。为此，在策略上定义一个 <code v-pre>before</code> 方法。<code v-pre>before</code> 方法将在策略上的任何其他方法之前执行，从而使您有机会在实际调用预期的策略方法之前授权操作。此功能最常用于授权应用程序管理员执行任何操作：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">before</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token variable">$ability</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">isSuperAdmin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token constant boolean">true</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果您想拒绝用户的所有授权，您应该从 <code v-pre>before</code> 方法返回 <code v-pre>false</code>。如果返回 <code v-pre>null</code>，则授权将传递给策略方法。</p>
<blockquote>
<p>注意：如果策略类的 <code v-pre>before</code> 方法不包含与正在检查的功能名称匹配的名称的方法，则不会调用该方法。</p>
</blockquote>
<h2 id="使用策略授权动作" tabindex="-1"><a class="header-anchor" href="#使用策略授权动作"><span>使用策略授权动作</span></a></h2>
<h3 id="通过用户模型" tabindex="-1"><a class="header-anchor" href="#通过用户模型"><span>通过用户模型</span></a></h3>
<p>Laravel 应用程序中包含的 <code v-pre>User</code> 模型包括两个用于授权操作的有用方法：<code v-pre>can</code> 和 <code v-pre>cant</code>。<code v-pre>can</code> 方法接收您希望授权的操作和相关模型。例如，让我们来确定一个用户是否被授权更新一个给定的 <code v-pre>Post</code> 模型:</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">//</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果为给定模型 <a href="#registering-policies">注册了策略</a>，<code v-pre>can</code> 方法将自动调用适当的策略并返回布尔结果。如果没有为模型注册策略，<code v-pre>can</code> 方法将尝试调用匹配给定操作名称的基于闭包的 Gate。</p>
<h4 id="不需要指定模型的动作" tabindex="-1"><a class="header-anchor" href="#不需要指定模型的动作"><span>不需要指定模型的动作</span></a></h4>
<p>记住，像 <code v-pre>create</code> 这样的操作可能不需要模型实例。在这些情况下，可以将类名传递给 <code v-pre>can</code> 方法。类名将用于确定在授权操作时使用哪个策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 在相关策略上执行 "create" 方法…</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="通过中间件" tabindex="-1"><a class="header-anchor" href="#通过中间件"><span>通过中间件</span></a></h3>
<p>Laravel 包含一个中间件，可以在传入的请求到达路由或控制器之前对操作进行授权。默认情况下，<code v-pre>Illuminate\Auth\Middleware\Authorize</code> 中间件被分配给 <code v-pre>App\Http\Kernel</code> 类中的 <code v-pre>can</code> 键。让我们来探索一个使用 <code v-pre>can</code> 中间件授权用户更新博客文章的例子：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{post}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以更新帖子…</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'can:update,post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在本例中，我们传递了 <code v-pre>can</code> 中间件两个参数。第一个是希望授权的操作的名称，第二个是希望传递给策略方法的路由参数。在本例中，由于我们使用<a href="https://learnku.com/docs/laravel/6.x/routing#implicit-binding" target="_blank" rel="noopener noreferrer">隐式模型绑定</a>，一个 <code v-pre>Post</code> 模型将被传递给策略方法。如果用户没有被授权执行给定的操作，则中间件将生成一个带有 <code v-pre>403</code> 状态代码的 HTTP 响应。</p>
<h4 id="不需要指定模型的动作-1" tabindex="-1"><a class="header-anchor" href="#不需要指定模型的动作-1"><span>不需要指定模型的动作</span></a></h4>
<p>同样，像 <code v-pre>create</code> 这样的一些操作可能不需要模型实例。在这些情况下，可以将类名传递给中间件。类名将用于确定在授权操作时使用哪个策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// 当前用户可以创建贴子…</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'can:create,App\Post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="通过控制器辅助函数" tabindex="-1"><a class="header-anchor" href="#通过控制器辅助函数"><span>通过控制器辅助函数</span></a></h3>
<p>除了为 <code v-pre>User</code> 模型提供的有用方法之外，Laravel 还为任何扩展 <code v-pre>App\Http\Controllers\Controller</code> 基类的控制器提供了一个有用的 <code v-pre>authorize</code> 方法。 与 <code v-pre>can</code> 方法一样，此方法接受您要授权的操作的名称和相关模型。 如果操作未被授权，<code v-pre>authorize</code>方法将抛出一个 <code v-pre>Illuminate\Auth\Access\AuthorizationException</code> ，默认的 Laravel 异常处理程序将转换为具有 <code v-pre>403</code> 状态代码的HTTP响应：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token doc-comment comment">/**</span>
<span class="line">     * 更新指定博客帖子。</span>
<span class="line">     *</span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name">Request</span>  <span class="token parameter">$request</span></span>
<span class="line">     * <span class="token keyword">@param</span>  <span class="token class-name">Post</span>  <span class="token parameter">$post</span></span>
<span class="line">     * <span class="token keyword">@return</span> <span class="token class-name">Response</span></span>
<span class="line">     * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line">     */</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">        <span class="token comment">// 当前用户可以更新博客....</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不需要指定模型的动作-2" tabindex="-1"><a class="header-anchor" href="#不需要指定模型的动作-2"><span>不需要指定模型的动作</span></a></h4>
<p>如前所述，像<code v-pre>create</code>这样的一些动作可能不需要模型实例。 在这些情况下，您应该将类名传递给<code v-pre>authorize</code>方法。 类名将用于确定授权操作时使用的策略：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 创建一个新的博客</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name">Request</span>  <span class="token parameter">$request</span></span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name">Response</span></span>
<span class="line"> * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">create</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// 当前用户可以新建博客...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="授权资源控制器" tabindex="-1"><a class="header-anchor" href="#授权资源控制器"><span>授权资源控制器</span></a></h4>
<p>如果你使用的是 <a href="https://learnku.com/docs/laravel/6.x/controllers#resource-controllers" target="_blank" rel="noopener noreferrer">资源控制器</a>，那么你就可以在控制器构造方法里使用 <code v-pre>authorizeResource</code> 方法。此方法将适当的 <code v-pre>can</code> 中间件定义附加到资源控制器相应的方法中。</p>
<p><code v-pre>authorizeResource</code> 方法接收模型类名作为第一个参数，以及路由名称 / 包含模型 ID 的请求参数作为其第二个参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Post</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">App<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Controllers<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">PostController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">authorizeResource</span><span class="token punctuation">(</span><span class="token class-name static-context">Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'post'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>以下控制器方法将映射到其对应的策略方法：</p>
<table>
<thead>
<tr>
<th>控制器方法</th>
<th>策略方法</th>
</tr>
</thead>
<tbody>
<tr>
<td>index</td>
<td>viewAny</td>
</tr>
<tr>
<td>show</td>
<td>view</td>
</tr>
<tr>
<td>create</td>
<td>create</td>
</tr>
<tr>
<td>store</td>
<td>create</td>
</tr>
<tr>
<td>edit</td>
<td>update</td>
</tr>
<tr>
<td>update</td>
<td>update</td>
</tr>
<tr>
<td>destroy</td>
<td>delete</td>
</tr>
</tbody>
</table>
<blockquote>
<p>{提示} 你可以使用带有 <code v-pre>--model</code> 选项的 <code v-pre>make:policy</code> 命令去快速生成基于给定模型的策略类：<code v-pre>php artisan make:policy PostPolicy --model=Post</code>。</p>
</blockquote>
<h3 id="通过-blade-模板" tabindex="-1"><a class="header-anchor" href="#通过-blade-模板"><span>通过 Blade 模板</span></a></h3>
<p>当编写 <code v-pre>Blade</code> 模板时，可能希望仅在用户被授权执行给定操作时才显示页面的一部分。比如，你可能希望仅在用户可以实际更新帖子时显示博客帖子的更新表单。在这样情况下，你可以使用 <code v-pre>@can</code> 和 <code v-pre>@cannot</code> 等一系列指令：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">@<span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 当前用户可以更新文章 <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line">@<span class="token function">elsecan</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 当前用户可以新建文章 <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line">@endcan</span>
<span class="line"></span>
<span class="line">@<span class="token function">cannot</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 当前用户不可以更新文章 <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line">@<span class="token function">elsecannot</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 当前用户不可以新建文章 <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line">@endcannot</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这些指令是编写 <code v-pre>@if</code> 和 <code v-pre>@unless</code> 语句的捷径。 <code v-pre>@can</code> 和 <code v-pre>@cannot</code> 语句分别转化为以下语句：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">@<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 当前用户可以更新文章 <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line">@<span class="token keyword">endif</span></span>
<span class="line"></span>
<span class="line">@<span class="token function">unless</span> <span class="token punctuation">(</span><span class="token class-name static-context">Auth</span><span class="token operator">::</span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 当前用户不可以更新文章 <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line">@endunless</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>您还可以确定用户是否具有来自给定能力列表的任何授权能力。 要实现这一点，请使用 <code v-pre>@ canany</code> 指令：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">@<span class="token function">canany</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'view'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'delete'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token comment">// 当前用户可以更新，查看和删除文章</span></span>
<span class="line">@<span class="token function">elsecanany</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token comment">// 当前用户可以创建文章</span></span>
<span class="line">@endcanany</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="不依赖模型的动作" tabindex="-1"><a class="header-anchor" href="#不依赖模型的动作"><span>不依赖模型的动作</span></a></h4>
<p>与大多数其他授权方法一样，如果动作不需要模型实例，则可以将类名传递给 <code v-pre>@ can</code> 和 <code v-pre>@ cannot</code> 指令：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">@<span class="token function">can</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 当前用户可以创建文章 <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line">@endcan</span>
<span class="line"></span>
<span class="line">@<span class="token function">cannot</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'create'</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">App<span class="token punctuation">\</span>Post</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 当前用户不可以创建文章 <span class="token operator">--</span><span class="token operator">></span></span>
<span class="line">@endcannot</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="提供附加上下文" tabindex="-1"><a class="header-anchor" href="#提供附加上下文"><span>提供附加上下文</span></a></h3>
<p>使用策略授权操作时，您可以将数组作为第二个参数传递给各种授权函数和辅助方法。 数组中的第一个元素将用于确定应调用哪个策略，而其余数组元素作为参数传递给策略方法，并可在进行授权决策时用于其他上下文。 例如，考虑以下 <code v-pre>PostPolicy</code> 方法定义，其中包含一个额外的 <code v-pre>$ category</code> 参数：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 确定用户是否可以更新给定的帖子。</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>User</span>  <span class="token parameter">$user</span></span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token punctuation">\</span>App<span class="token punctuation">\</span>Post</span>  <span class="token parameter">$post</span></span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name"><span class="token keyword">int</span></span>  <span class="token parameter">$category</span></span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name"><span class="token keyword">bool</span></span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">User</span> <span class="token variable">$user</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">,</span> <span class="token keyword type-hint">int</span> <span class="token variable">$category</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token property">id</span> <span class="token operator">===</span> <span class="token variable">$post</span><span class="token operator">-></span><span class="token property">user_id</span> <span class="token operator">&amp;&amp;</span> </span>
<span class="line">           <span class="token variable">$category</span> <span class="token operator">></span> <span class="token number">3</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在尝试确定验证过的用户是否可以更新给定文章时，我们可以像这样调用此策略方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * 更新给定的博客文章.</span>
<span class="line"> *</span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name">Request</span>  <span class="token parameter">$request</span></span>
<span class="line"> * <span class="token keyword">@param</span>  <span class="token class-name">Post</span>  <span class="token parameter">$post</span></span>
<span class="line"> * <span class="token keyword">@return</span> <span class="token class-name">Response</span></span>
<span class="line"> * <span class="token keyword">@throws</span> <span class="token class-name"><span class="token punctuation">\</span>Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Access<span class="token punctuation">\</span>AuthorizationException</span></span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Post</span> <span class="token variable">$post</span><span class="token punctuation">)</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">authorize</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'update'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token variable">$post</span><span class="token punctuation">,</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">input</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'category'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">//当前用户可以更新这篇博客文章...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/6.x/authorization/5153" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/6.x/aut...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/6.x/authorization/5153" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/6.x/aut...</a></p>
</blockquote>
</div></template>


